﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;

namespace MysToolCore
{
    /// <summary>
    /// 扩展方法类
    /// </summary>
    [Description("MysTool的扩展方法")]
    public static partial class Core {


        public static T GetMinValue<T>() where T : INumber<T>
        {
            return typeof(T) switch
            {
                Type t when t == typeof(int) => (T)(object)int.MinValue,
                Type t when t == typeof(long) => (T)(object)long.MinValue,
                Type t when t == typeof(double) => (T)(object)double.MinValue,
                Type t when t == typeof(double) => (T)(object)double.MinValue,
                Type t when t == typeof(decimal) => (T)(object)decimal.MinValue,
                _ => throw new NotSupportedException($"Type {typeof(T)} is not supported.")
            };
        }

        public static T GetMaxValue<T>() where T : INumber<T>
        {
            return typeof(T) switch
            {
                Type t when t == typeof(int) => (T)(object)int.MaxValue,
                Type t when t == typeof(long) => (T)(object)long.MaxValue,
                Type t when t == typeof(double) => (T)(object)double.MaxValue,
                Type t when t == typeof(double) => (T)(object)double.MaxValue,
                Type t when t == typeof(decimal) => (T)(object)decimal.MaxValue,
                _ => throw new NotSupportedException($"Type {typeof(T)} is not supported.")
            };
        }
        /// <summary>
        /// 计算 Span<T> 中的最大值
        /// </summary>
        public static T Max<T>(this Span<T> span) where T:INumber<T>
        {
            if (span.Length == 0)
                throw new InvalidOperationException("Cannot compute max of an empty span.");
            T max=GetMinValue<T>();
            foreach (var value in span)
            {
                if (value > max)
                    max = value;
            }
            return max;
        }

        /// <summary>
        /// 计算 Span<T> 中的最小值
        /// </summary>
        public static T Min<T>(this Span<T> span) where T : INumber<T>
        {
            if (span.Length == 0)
                throw new InvalidOperationException("Cannot compute min of an empty span.");

            T min = GetMaxValue<T>();
            foreach (var value in span)
            {
                if (value < min)
                    min = value;
            }
            return min;
        }

        /// <summary>
        /// 计算 Span<double> 中的中位数
        /// </summary>
        public static double Median(this Span<double> span)
        {
            if (span.Length == 0)
                throw new InvalidOperationException("Cannot compute median of an empty span.");

            var sortedArray = span.ToArray();
            Array.Sort(sortedArray);
            int count = sortedArray.Length;

            if (count % 2 == 1)
            {
                return sortedArray[count / 2];
            }
            else
            {
                return (sortedArray[(count - 1) / 2] + sortedArray[count / 2]) / 2;
            }
        }

        /// <summary>
        /// 计算 Span<T> 中的平均值
        /// </summary>
        public static double Average<T>(this Span<T> span) where T:INumber<T>
        {
            if (span.Length == 0)
                throw new InvalidOperationException("Cannot compute average of an empty span.");

            T sum = T.Zero;
            foreach (var value in span)
            {
                sum += value;
            }
            // 使用 ToDouble 方法来确保除法操作的精度
            
            T lengthAsDouble =T.CreateChecked(span.Length);
            return double.CreateChecked(sum / lengthAsDouble);
        }

        /// <summary>
        /// 计算 Span<double> 中的样本方差
        /// </summary>
        public static double Variance<T>(this Span<T> span) where T : INumber<T>
        {
            if (span.Length <= 1)
                throw new InvalidOperationException("Cannot compute variance of a span with less than two elements.");

            double avg = span.Average();
            var varianceSum = T.Zero;

            foreach (var value in span)
            {
                var diff = value - T.CreateChecked(avg);
                varianceSum += diff * diff;
            }
            var bc=T.CreateChecked((span.Length - 1));
            return double.CreateChecked(varianceSum /bc);
        }


        /// <summary>
        /// 计算 Span<double> 中的中位数
        /// </summary>
        public static T Median<T>(this Span<T> span) where T : INumber<T>
        {
            int count = span.Length;
            if (count == 0)
                throw new InvalidOperationException("Cannot compute median of an empty span.");

            // 创建一个可排序的副本，以避免修改原始数据
            T[] sortedArray = span.ToArray();
            Array.Sort(sortedArray);
            return sortedArray[count / 2];
        }

        ///// <summary>
        ///// 使用部分排序算法计算中位数
        ///// </summary>
        //public static T MedianInPlace<T>(this Span<T> span) where T : INumber<T>
        //{
        //    int count = span.Length;
        //    if (count == 0)
        //        throw new InvalidOperationException("Cannot compute median of an empty span.");

        //    // 使用快速选择算法找到中位数的位置
        //    int midIndex = count / 2;
        //    // 对于奇数个元素，直接找到中间元素
        //    QuickSelect(span, midIndex);
        //    return span[midIndex];
        //}

        //private static void QuickSelect<T>(Span<T> span, int k) where T : INumber<T>
        //{
        //    int left = 0;
        //    int right = span.Length - 1;

        //    while (true)
        //    {
        //        if (left == right)
        //            return;

        //        int pivotIndex = Partition(span, left, right);
        //        if (pivotIndex == k)
        //            return;
        //        else if (pivotIndex > k)
        //            right = pivotIndex - 1;
        //        else
        //            left = pivotIndex + 1;
        //    }
        //}

        //private static int Partition<T>(Span<T> span, int left, int right) where T : INumber<T>
        //{
        //    T pivotValue = span[right];
        //    int i = left - 1;

        //    for (int j = left; j < right; j++)
        //    {
        //        if (span[j] <= pivotValue)
        //        {
        //            i++;
        //            (span[i], span[j]) = (span[j], span[i]);
        //        }
        //    }

        //    (span[i + 1], span[right]) = (span[right], span[i + 1]);
        //    return i + 1;
        //}
    }


}